import { AmmoLib } from '../AmmoLib.js'
import { WuLiWuTi } from './WuLiWuTi.js'

class WuLiGangTi extends WuLiWuTi {
	xingZhuangTi = null
	xingZhuang = null
	jianGe = 0.05 // 间隔
	zhiLiang = null
	shiJie = null // 物理世界
	wuTi = null
	wuTiLeiXing = '刚体'
	
	constructor(canShu, shiJie) {
		super()
		
		this.bianHao = canShu.bianHao
		this.mingZi = canShu.mingZi
		this.zhiLiang = canShu.zhiLiang
		this.shiJie = shiJie
		this.xingZhuangTi = this.shengChengXingZhuangTi(canShu.pengZhuangTi)
		this.xingZhuang = canShu.pengZhuangTi.xingZhuang
		this.wuTi = this.shengChengWuTi(canShu)
		shiJie.addRigidBody(this.wuTi)
	}
	
	// 生成形状 原点为几何中心
	shengChengXingZhuangTi(pengZhuangTi) {
		let { xingZhuang } = pengZhuangTi
		// 组合形状
		if (xingZhuang == '组合' && Array.isArray(pengZhuangTi.zi)) {
			let compound = new AmmoLib.btCompoundShape();
			for (let pzt of pengZhuangTi.zi) {
				let { suoFang, xuanZhuan ,weiZhi } = pzt
				let btv3 = new AmmoLib.btVector3(0, 0, 0)
				let quaternion = new AmmoLib.btQuaternion()
				let localTrans = new AmmoLib.btTransform()
				localTrans.setIdentity()

				let xingZhuangTi = this.shengChengXingZhuangTi(pzt)

				if (suoFang) {
					btv3.setValue(...suoFang)
					xingZhuangTi.setLocalScaling(btv3)
				}
				if (xuanZhuan) {
					quaternion.setValue(...xuanZhuan)
					localTrans.setRotation(quaternion)
				}
				if (weiZhi) {
					btv3.setValue(...weiZhi)
					localTrans.setOrigin(btv3)
				}

				compound.addChildShape(localTrans, xingZhuangTi)
				
				AmmoLib.destroy(btv3)
				AmmoLib.destroy(quaternion)
				AmmoLib.destroy(localTrans)
			}
			compound.setMargin(this.jianGe)
			return compound
		}
		// 人物胶囊
		if (xingZhuang === '胶囊') {
			let { radius, length } = pengZhuangTi.chiCun
			let shape = new AmmoLib.btCapsuleShape(radius, length)
			shape.setMargin(this.jianGe)
			return shape
		}

		// 方体
		if (xingZhuang === '方体') {
			let { width, height, depth } = pengZhuangTi.chiCun
			const sx = width / 2
			const sy = height / 2
			const sz = depth / 2
			let btV3 = new AmmoLib.btVector3(sx, sy, sz)
			const shape = new AmmoLib.btBoxShape(btV3)
			AmmoLib.destroy(btV3)
			shape.setMargin(this.jianGe)
			return shape
		}
		// 球
		if (xingZhuang === '球体') {
			const radius = pengZhuangTi.chiCun.radius
			const shape = new AmmoLib.btSphereShape(radius)
			shape.setMargin(this.jianGe)
			return shape
		}
		// 圆锥
		if (xingZhuang === '圆锥') {
			const { radius, height } = pengZhuangTi.chiCun
			const shape = new AmmoLib.btConeShape(radius, height)
			shape.setMargin(this.jianGe)
			return shape
			
		}
		// 圆柱
		if (xingZhuang === '圆柱') {
			const { radiusBottom, height } = pengZhuangTi.chiCun
			let btv3 = new AmmoLib.btVector3(radiusBottom, height / 2, radiusBottom)
			const shape = new AmmoLib.btCylinderShape(btv3)
			shape.setMargin(this.jianGe)
			AmmoLib.destroy(btv3)
			return shape
		}
		// 动态物体 凸形类型
		if (xingZhuang === '凸几何') {
			let coords = pengZhuangTi.dingDian
			let shape = new AmmoLib.btConvexHullShape()
			let tempBtVec3_1 = new AmmoLib.btVector3()
			
			for (let i = 0, il = coords.length; i < il; i += 3) {
				tempBtVec3_1.setValue(coords[i], coords[i + 1], coords[i + 2])
				const lastOne = (i >= (il - 3))
				shape.addPoint(tempBtVec3_1, lastOne)
			}
			shape.setMargin(this.jianGe)
			AmmoLib.destroy(tempBtVec3_1)
			return shape
		}
		// 地形
		if (xingZhuang === '地形') {
			let { chiCun: { width, height, widthSegments, heightSegments }, dingDian} = pengZhuangTi
			let heightData = []
			for ( let i = 0, l = dingDian.length; i < l; i += 3 ) {
				heightData.push(dingDian[ i + 1 ])
			}
			let maxY = heightData.reduce((a, b) => Math.max(a, b), -Infinity);
			let minY = heightData.reduce((a, b) => Math.min(a, b), Infinity);

			const heightScale = 1;
			const upAxis = 1; // Up axis = 0 for X, 1 for Y, 2 for Z. Normally 1 = Y is used.
			const hdt = 'PHY_FLOAT';
			const flipQuadEdges = false;
			let ammoHeightData = AmmoLib._malloc( 4 * widthSegments * heightSegments );
			let p = 0;
			let p2 = 0;
			for ( let j = 0; j < heightSegments; j ++ ) {
				for ( let i = 0; i < widthSegments; i ++ ) {
					AmmoLib.HEAPF32[ ammoHeightData + p2 >> 2 ] = heightData[ p ];
					p ++;
					p2 += 4;
				}
			}
			const shape = new AmmoLib.btHeightfieldTerrainShape(
				widthSegments + 1,
				heightSegments + 1,
				ammoHeightData,
				heightScale,
				minY,
				maxY,
				upAxis,
				hdt,
				flipQuadEdges
			)
			const scaleX = width / widthSegments;
			const scaleZ = height / heightSegments;
			shape.setLocalScaling( new AmmoLib.btVector3( scaleX, 1, scaleZ ) );
			shape.setMargin( 0.05 );
			return shape;
		}
		// 此形状只能用于静态物体，默认情况下 addTriangle 不会搜索重复的顶点
		if (xingZhuang === '静三角') {
			const coords = pengZhuangTi.dingDian
			let mesh = new AmmoLib.btTriangleMesh(true, true)
		
			for (let i = 0; i < coords.length; i += 9) {
				let v1 = new AmmoLib.btVector3(coords[i], coords[i + 1], coords[i + 2])
				let v2 = new AmmoLib.btVector3(coords[i + 3], coords[i + 4], coords[i + 5])
				let v3 = new AmmoLib.btVector3(coords[i + 6], coords[i + 7], coords[i + 8])
				mesh.addTriangle(v1, v2, v3, false)
				AmmoLib.destroy(v1)
				AmmoLib.destroy(v2)
				AmmoLib.destroy(v3)
			}
			let shape = new AmmoLib.btBvhTriangleMeshShape(mesh, true, true)
			shape.setMargin(this.jianGe)
			return shape
		}
		// 动三角
		if (xingZhuang === '动三角') {
			const coords = pengZhuangTi.dingDian
			let mesh = new AmmoLib.btTriangleMesh()
		
			for (let i = 0; i < coords.length; i += 9) {
				let v1 = new AmmoLib.btVector3(coords[i], coords[i + 1], coords[i + 2])
				let v2 = new AmmoLib.btVector3(coords[i + 3], coords[i + 4], coords[i + 5])
				let v3 = new AmmoLib.btVector3(coords[i + 6], coords[i + 7], coords[i + 8])
				mesh.addTriangle(v1, v2, v3, false)
				AmmoLib.destroy(v1)
				AmmoLib.destroy(v2)
				AmmoLib.destroy(v3)
			}
			let shape = new AmmoLib.btGImpactMeshShape(mesh)
			shape.setMargin(this.jianGe)
			shape.setLocalScaling(new AmmoLib.btVector3(1, 1, 1))
			shape.updateBound()
			return shape
		}
		
		return null
	}
	// 编辑组合形状，质心为组合形状的原点
	bianJiXingZhuang(canShu) {
		if (this.xingZhuang !== '组合') return

		let { bianJiLeiXing, pengZhuangTi, sheZhi, suoYin } = canShu

		// btRigidBody.getCollisionShape() 返回的不是本体形状，用法不清楚
		let zuHeXingZhuangTi = this.xingZhuangTi

		let bianHuan = new AmmoLib.btTransform()
		let vec3 = new AmmoLib.btVector3(0, 0, 0)
		let quaternion = new AmmoLib.btQuaternion()

		bianHuan.setIdentity()

		if (bianJiLeiXing === 0) {
			let { suoFang, xuanZhuan, weiZhi } = pengZhuangTi

			let xingZhuangTi = this.shengChengXingZhuangTi(pengZhuangTi)
			vec3.setValue(...suoFang)
			xingZhuangTi.setLocalScaling(vec3)

			quaternion.setValue(...xuanZhuan)
			bianHuan.setRotation(quaternion)

			vec3.setValue(...weiZhi)
			bianHuan.setOrigin(vec3)

			zuHeXingZhuangTi.addChildShape(bianHuan, xingZhuangTi)
		}

		if (bianJiLeiXing === 1) {
			let { suoFang, xuanZhuan, weiZhi } = sheZhi

			let xingZhuangTi = zuHeXingZhuangTi.getChildShape(suoYin)
			vec3.setValue(...suoFang)
			xingZhuangTi.setLocalScaling(vec3)

			quaternion.setValue(...xuanZhuan)
			bianHuan.setRotation(quaternion)

			vec3.setValue(...weiZhi)
			bianHuan.setOrigin(vec3)

			zuHeXingZhuangTi.updateChildTransform(suoYin, bianHuan, true)
		}

		if (bianJiLeiXing === 2) {
			zuHeXingZhuangTi.removeChildShapeByIndex(suoYin)
		}

		AmmoLib.destroy(bianHuan)
		AmmoLib.destroy(vec3)
		AmmoLib.destroy(quaternion)
	}
	// 生成物体
	shengChengWuTi(canShu) {
		let { xuanZhuan, weiZhi, suoFang, zhiLiang } = canShu
		const transform = new AmmoLib.btTransform()
		transform.setIdentity()
		transform.setRotation(new AmmoLib.btQuaternion(...xuanZhuan))
		transform.setOrigin(new AmmoLib.btVector3(...weiZhi))
		
		const motionState = new AmmoLib.btDefaultMotionState(transform)
		const localInertia = new AmmoLib.btVector3(0, 0, 0)
		
		let body
		
		this.xingZhuangTi.calculateLocalInertia(zhiLiang, localInertia)
		this.xingZhuangTi.setLocalScaling(new AmmoLib.btVector3(...suoFang))

		const rbInfo = new AmmoLib.btRigidBodyConstructionInfo(zhiLiang, motionState, this.xingZhuangTi, localInertia)
		body = new AmmoLib.btRigidBody(rbInfo)
		
		body.setFriction(4) // 摩擦力
		// body.setMassProps(0) // 设置质量
		
		body.setSleepingThresholds(0.0, 0.0) // 不休眠（一直是活动物体
		// body.setAngularFactor(0) // 0禁止旋转
		
		// 快速物体开启连续检测
		// body.setCcdMotionThreshold(0.5) // 运动距离大于0.5开启
		// body.setCcdSweptSphereRadius(0.1)
		
		// 动态物体
		// 设置激活 ACTIVE_TAG1, ISLAND_SLEEPING2, WANTS_DEACTIVATION3, DISABLE_DEACTIVATION4, DISABLE_SIMULATION5
		body.setActivationState(4)
		
		return body
	}
	// 缩放 旋转 平移 固定顺序
	sheZhiWuTi(canShu) {
		// 质量0静态物体不能设置位置等状态
		let { bianHao, xuanZhuan, suoFang, weiZhi, xianSuDu, jiaXianSuDu, jiaoSuDu, shouLi, zhongLi, chongLiang, moCa, xianZuLi, jiaoZuLi } = canShu
		const body = this.wuTi
		const btV3 = new AmmoLib.btVector3()
		const btQ = new AmmoLib.btQuaternion()
		const transform = new AmmoLib.btTransform()
		if (!(body.getMotionState instanceof Function)) return;
		const motionState = body.getMotionState()
		// 同一帧的设置sheZhiWuTi只能调一次，不然body设置状态会失效
		transform.setIdentity()
		motionState.getWorldTransform(transform)
		
		// 设置摩擦
		if (moCa !== undefined) {
			body.setFriction(moCa)
		}
		// 
		if (isFinite(xianZuLi) || isFinite(jiaoZuLi)) {
			xianZuLi ??= 0
			jiaoZuLi ??= 0
			body.setDamping(xianZuLi, jiaoZuLi)
		}
		// 单独设置重力需加入世界后才生效
		if (zhongLi) {
			// 重力值是加速度
			btV3.setValue(...zhongLi)
			body.setGravity(btV3)
		}
		// 力需要持续添加
		if (shouLi) {
			// body.clearForces()
			btV3.setValue(...shouLi)
			body.applyCentralForce(btV3) // 作用中心力
		
			// body.applyForce(li, dian) // 作用点力
		}
		if (chongLiang) {
			btV3.setValue(...chongLiang)
			body.applyCentralImpulse(btV3) // 作用中心冲量
		
			// body.applyImpulse(li, dian) // 作用点冲量
		}
		// 设置线速度
		if (xianSuDu) {
			btV3.setValue(...xianSuDu)
			body.setLinearVelocity(btV3)
		}
		// 与原线速度相加
		if (jiaXianSuDu) {
			btV3.setValue(...jiaXianSuDu)
			let yuanSuDu = body.getLinearVelocity()
			yuanSuDu.op_add(btV3)
			body.setLinearVelocity(yuanSuDu)
		}
		if (jiaoSuDu) {
			btV3.setValue(...jiaoSuDu)
			body.setAngularVelocity(btV3)
		}
		// 设置旋转
		if (suoFang) {
			let xingZhuangTi = body.getCollisionShape()
			btV3.setValue(...suoFang)
			xingZhuangTi.setLocalScaling(btV3)
		}
		// 设置旋转
		if (xuanZhuan) {
			btQ.setValue(...xuanZhuan)
			transform.setRotation(btQ)
		}
		// 设置平移位置
		if (weiZhi) {
			btV3.setValue(...weiZhi)
			transform.setOrigin(btV3)
		}
		
		// body.setWorldTransform(transform)
		motionState.setWorldTransform(transform)
		body.setMotionState(motionState)

		// 先销毁最后创建的
		AmmoLib.destroy(transform)
		AmmoLib.destroy(btV3)
		AmmoLib.destroy(btQ)
	}
	// 更新物体
	gengXinWuTi() {
		const motionState = this.wuTi.getMotionState()
		const transform = new AmmoLib.btTransform()
		motionState.getWorldTransform(transform)
		const position = transform.getOrigin()
		const quaternion = transform.getRotation()
		let jieGuo = {
			bianHao: this.bianHao,
			mingZi: this.mingZi,
			weiZhi: [position.x(), position.y(), position.z()],
			xuanZhuan: [quaternion.x(), quaternion.y(), quaternion.z(), quaternion.w()]
		}

		AmmoLib.destroy(transform)
		return jieGuo
	}
	// 销毁物体
	xiaoHuiWuTi() {
		this.shiJie.removeRigidBody(this.wuTi)
		AmmoLib.destroy(this.xingZhuangTi)
		AmmoLib.destroy(this.wuTi)
	}
}

export {
	WuLiGangTi
}